/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "imageknife_node_internal.h"
#include "border_option_napi.h"
#include "imageknife_node_animator.h"
#include "option/imageknife_option_napi.h"
#include "request/imageknife_request_internal.h"
#include "imageknife_node_image.h"
#include "imageknife_internal.h"

namespace ImageKnifeC {

// static
std::shared_ptr<ImageKnifeNode> ImageKnifeNode::CreateImageKnifeNode(std::string componentId,
    std::shared_ptr<ImageKnifeOption> option)
{
    return std::make_shared<ImageKnifeNodeImage>(componentId, option);
}

// static
std::shared_ptr<ImageKnifeNode> ImageKnifeNode::CreateImageKnifeNodeAnimator(std::string componentId,
    std::shared_ptr<ImageKnifeOption> option, std::shared_ptr<AnimatorOption> animatorOption)
{
    return std::make_shared<ImageKnifeNodeAnimator>(componentId, option, animatorOption);
}

// static
void ImageKnifeNodeInternal::OnNodeEvent(ArkUI_NodeEvent *event)
{
    auto nodeHandle = OH_ArkUI_NodeEvent_GetNodeHandle(event);
    ImageKnifeNodeInternal *node = reinterpret_cast<ImageKnifeNodeInternal *>(GetNodeAPI()->getUserData(nodeHandle));
    auto eventType = OH_ArkUI_NodeEvent_GetEventType(event);

    switch (eventType) {
        case NODE_EVENT_ON_AREA_CHANGE:
            node->OnAreaChange(event);
            break;
        default:
            node->OnDerivedNodeEvent(event);
            return;
    }
}

void ImageKnifeNodeInternal::OnAreaChange(ArkUI_NodeEvent *event)
{
    enum ComponentEventDataIndex {
        OLD_WIDTH_INDEX = 0,
        OLD_HEIGHT_INDEX = 1,
        WIDTH_INDEX = 6,
        HEIGHT_INDEX = 7,
    };

    auto componetEvent = OH_ArkUI_NodeEvent_GetNodeComponentEvent(event);

    width_ = componetEvent->data[WIDTH_INDEX].f32;
    height_ = componetEvent->data[HEIGHT_INDEX].f32;
    
    if ((width_ != componetEvent->data[OLD_WIDTH_INDEX].f32) ||
        (height_ != componetEvent->data[OLD_HEIGHT_INDEX].f32)) {
        ImageKnifeInternal::GetInstance().Execute(imageKnifeRequest_);
    }
}

void ImageKnifeNodeInternal::SetBorder()
{
    auto optionNapi = std::dynamic_pointer_cast<ImageKnifeOptionNapi>(imageKnifeRequest_->GetImageKnifeOption());
    if (optionNapi == nullptr) {
        return;
    }
    BorderOptionNapi *border = dynamic_cast<BorderOptionNapi*>(optionNapi->border);
    if (border == nullptr) {
        return;
    }
    for (int i = 0; i < sizeof(border->width) / sizeof(border->width[0]); i++) {
        borderWidth_[i].f32 = border->width[i];
        borderRadius_[i].f32 = border->radius[i];
        borderColor_[i].u32 = border->color[i];
        borderStyle_[i].i32 = border->style[i];
    }

    if (border->hasWidth) {
        ArkUI_AttributeItem item = { .value = borderWidth_, .size=1};
        GetNodeAPI()->setAttribute(handle, NODE_BORDER_WIDTH, &item);
    }

    if (border->hasRadius) {
        ArkUI_AttributeItem item = { .value = borderRadius_, .size=1};
        GetNodeAPI()->setAttribute(handle, NODE_BORDER_RADIUS, &item);
    }

    if (border->hasStyle) {
        ArkUI_AttributeItem item = { .value = borderStyle_, .size=1};
        GetNodeAPI()->setAttribute(handle, NODE_BORDER_STYLE, &item);
    }
}

void ImageKnifeNodeInternal::UpdateImageKnifeRequest(std::shared_ptr<ImageKnifeOption> option)
{
    imageKnifeRequest_ = std::make_shared<ImageKnifeRequestInternal>(componentId_, option, GetNodeVersion());

    UpdateDerivedNodeEvent(option);
    SetBorder();
}

void ImageKnifeNodeInternal::SyncLoad(bool syncLoad)
{
    static_cast<ImageKnifeRequestInternal*>(imageKnifeRequest_.get())->SyncLoad(syncLoad);
}

void ImageKnifeNodeInternal::SetWidth(float width)
{
    ArkUI_NumberValue value = {.f32 = width};
    ArkUI_AttributeItem item = {&value, 1};
    GetNodeAPI()->setAttribute(handle, NODE_WIDTH, &item);
}

void ImageKnifeNodeInternal::SetPercentWidth(float percent)
{
    ArkUI_NumberValue value = {.f32 = percent};
    ArkUI_AttributeItem item = {&value, 1};
    GetNodeAPI()->setAttribute(handle, NODE_WIDTH_PERCENT, &item);
}

void ImageKnifeNodeInternal::SetHeight(float height)
{
    ArkUI_NumberValue value = {.f32 = height};
    ArkUI_AttributeItem item = {&value, 1};
    GetNodeAPI()->setAttribute(handle, NODE_HEIGHT, &item);
}

void ImageKnifeNodeInternal::SetPercentHeight(float percent)
{
    ArkUI_NumberValue value = {.f32 = percent};
    ArkUI_AttributeItem item = {&value, 1};
    GetNodeAPI()->setAttribute(handle, NODE_HEIGHT_PERCENT, &item);
}

} // end of namespace